package com.ljs.module.util;

import com.ljs.module.SimpleDevelop;
import com.ljs.module.entity.ConfigProperties;
import com.ljs.module.entity.common.TreeNode;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.boot.ApplicationHome;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;

/**
 * Created by lijunsai on 2021/08/23
 */
public class FileUtil {
    public static String basePath = "";
    public static final String EXT_PATH = "/src/web/vision/js/ext/";

    static {
        // 初始化，获取jar包路径，读取config中的配置
        ApplicationHome ah = new ApplicationHome(SimpleDevelop.class);
        try {
            basePath = ah.getSource().getParentFile().toString();
        } catch (Exception e) {
            basePath = ah.getDir().toString();
        }
    }

    public static void writeContent2File(String path, String content) {
        File file = new File(path);
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            fos.write(content.getBytes("UTF-8"));
            fos.flush();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 获取文件全部内容
     * @param path 文件路径
     * @return 如果文件不存在 或内容为空 就返回null
     */
    public static String readFile2Content(String path) {
        File file = new File(path);
        if (file.exists() && file.length() > 0) {
            FileInputStream fis = null;
            try {
                fis = new FileInputStream(file);
                byte[] content = new byte[((Long)file.length()).intValue()];
                fis.read(content);
                fis.close();
                return new String(content, "UTF-8");
            } catch (Exception e) {
                return null;
            } finally {
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
        return null;
    }

    /**
     * 插入文件
     * @param filePath 文件路径
     * @param sb 文件内容
     * @return 操作结果
     * @throws IOException
     */
    public static String insertFile(String filePath, String sb) throws IOException {
        // 存储js文件
        File file = new File(filePath);
        if (!file.exists()) {
            file.createNewFile();
            FileOutputStream fis = new FileOutputStream(file);
            fis.write(sb.getBytes("UTF-8"));
            fis.close();
            return filePath + " 添加成功<br>";
        } else {
            return filePath + " 已存在<br>";
        }
    }

    /**
     * 插入系统配置项文件
     * @param path 扩展包路径
     * @param sb 文件内容
     * @param fileName 文件名
     * @return 操作结果
     * @throws IOException
     */
    public static String insertConfigJsFile(String path, StringBuilder sb, String fileName, ConfigProperties configProperties) throws IOException {
        File file = new File(path, EXT_PATH + "config" + File.separator);
        if (!file.exists()) {
            file.mkdirs();
        }
        // 存储js文件
        file = new File(path, EXT_PATH + "config" + File.separator + fileName + ".js");
        if (!file.exists()) {
            file.createNewFile();
            FileOutputStream fis = new FileOutputStream(file);
            fis.write(sb.toString().getBytes("UTF-8"));
            fis.close();
            return fileName + ".js 文件已添加到" + path + EXT_PATH + "config/ 路径下<br>";
        } else {
            if (configProperties.isOverride()) {
                FileOutputStream fis = new FileOutputStream(file);
                fis.write(sb.toString().getBytes("UTF-8"));
                fis.close();
                return fileName + ".js已存在，执行覆盖操作<br>";
            } else {
                return fileName + ".js已存在，添加失败<br>";
            }
        }
    }

    /**
     * 通过扩展包路径  找到applicationContext.xml中的Module实现类的路径
     * @param projectPath 扩展包路径
     * @return Module路径
     */
    public static List<String> findModulePath(String projectPath) {
        String applicationContextPath = projectPath;
        if (!projectPath.contains(File.separator + "src" + File.separator + "web" + File.separator + "META-INF" + File.separator + "applicationContext.xml")) {
            applicationContextPath += File.separator + "src" + File.separator + "web" + File.separator + "META-INF" + File.separator + "applicationContext.xml";
        }
        //1.创建DocumentBuilderFactory对象
//        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        //2.创建DocumentBuilder对象
        try {
            Document document = new SAXReader().read(new File(applicationContextPath));
            Element rootElement = document.getRootElement();
            List<Element> beans = rootElement.elements("bean");

            List<String> moduleNames = new ArrayList<>();
            Map<String, String> packages = new HashMap<>();
            for (Element bean : beans) {
                String id = bean.attribute("id").getText();
                String packageName = bean.attribute("class").getText();
                packages.put(id, packageName);
                if (id.equals("framework")) {
                    List<Element> propertys = bean.elements("property");
                    for (Element property : propertys) {
                        moduleNames = property.element("map")
                                .elements("entry")
                                .stream()
                                .map(x -> x.element("ref").attribute("bean").getText())
                                .collect(Collectors.toList());
                    }
                }
            }
            List<String> packagePaths = moduleNames.stream()
                    .map(x -> packages.get(x)).collect(Collectors.toList());
            return packagePaths;
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 文件夹不存在 则创建
     * @param path 文件夹路径
     */
    public static void directoryNotExistThenMake(String path) {
        File file = new File(path);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    /**
     * 文件不存在 则创建
     * @param path 文件路径
     * @throws IOException
     */
    public static void fileNotExistThenMake(String path){
        File file = new File(path);
        if (!file.exists()) {
            try {
                file.createNewFile();
            } catch (IOException e) {
                System.err.print("新建文件失败:" + path);
            }
        }
    }

    public static String getFileCharsetName(String filePath) throws IOException {
        InputStream inputStream = new FileInputStream(filePath);
        byte[] head = new byte[3];
        inputStream.read(head);
        String charsetName = "GBK";//或GB2312，即ANSI
        if (head[0] == -1 && head[1] == -2 ) //0xFFFE
            charsetName = "UTF-16";
        else if (head[0] == -2 && head[1] == -1 ) //0xFEFF
            charsetName = "Unicode";//包含两种编码格式：UCS2-Big-Endian和UCS2-Little-Endian
        else if(head[0]==-27 && head[1]==-101 && head[2] ==-98)
            charsetName = "UTF-8"; //UTF-8(不含BOM)
        else if(head[0]==-17 && head[1]==-69 && head[2] ==-65)
            charsetName = "UTF-8"; //UTF-8-BOM
        inputStream.close();
        return charsetName;
    }

    /**
     * 将集合的数据按行载入文件
     * @param path 文件路径
     * @param list 需要被载入的集合
     * @param action 数据处理方式
     */
    public static <T> void changeExtList(String path, List<T> list, Function<T,String> action) {
        File file = new File(path);
        BufferedWriter writer = null;
        try {
            writer = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(file)));
            for (T t : list) {
                writer.write(action.apply(t));
                writer.newLine();
            }
        } catch (Exception e) {

        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 从指定文件中按行读取数据
     * @param path 指定文件路径
     * @param collector 添加到这个集合中
     * @param action 每行数据的处理方式
     */
    public static <T, A, R>  R loadExtList(String path, Collector<? super T, A, R> collector, Function<String, T> action) {
        List<T> list = new ArrayList<>();
        File file = new File(path);
        BufferedReader reader = null;
        try {
            reader = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
            String temp = "";
            while ((temp = reader.readLine()) != null) {
                list.add(action.apply(temp));
            }
        } catch (Exception e) {

        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return list.stream().collect(collector);
    }

    public static List<TreeNode> getTreeNode(String filePath, String prePath, String endWith, boolean havaChildren) {
        File file = new File(filePath);
        File[] files = file.listFiles(x -> x.isDirectory() || x.getName().endsWith(endWith));
        if (files == null || files.length == 0) {
            return new ArrayList<>();
        }
        if (havaChildren) {
            return Arrays.stream(files).map(x -> {
                String nowPath = prePath + File.separator + x.getName();
                List<TreeNode> nodes = x.isFile() ? new ArrayList<>() : getTreeNode(filePath + File.separator + x.getName(), nowPath, endWith, havaChildren);
                return new TreeNode(nowPath, x.getName(), x.isFile(), nowPath, nodes);
            }).collect(Collectors.toList());
        } else {
            List<TreeNode> directory = new ArrayList<>();
            List<TreeNode> nodes = Arrays.stream(files).filter(x -> {
                String nowPath = prePath + File.separator + x.getName();
                if (x.isDirectory()) {
                    directory.addAll(getTreeNode(filePath + File.separator + x.getName(), nowPath, endWith, havaChildren));
                }
                return x.isFile();
            }).map(x -> {
                String name = x.getName();
                String substringName = name.substring(0, name.indexOf("."));
                String nowPath = prePath + Util.getNowFileSepartor() + substringName;
                nowPath = nowPath.substring(1);
                return new TreeNode(nowPath, substringName, x.isFile(), nowPath, null);
            }).collect(Collectors.toList());
            nodes.addAll(directory);
            return nodes;
        }
    }
}
